package be.ac.ua.auctioneer;

import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Date;

import distrcomp.ShippingState;

import net.jini.core.entry.UnusableEntryException;
import net.jini.core.event.UnknownEventException;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.transaction.TransactionException;
import be.ac.ua.codebase.Bidding;
import be.ac.ua.codebase.Product;
import be.ac.ua.codebase.ProductOffer;
import be.ac.ua.codebase.WinningEvent;

public abstract class DutchAuctioneer extends AuctioneerImplementation {

	private double nextMax;
	
	public DutchAuctioneer(AuctioneerManager manager, ProductOffer productOffer) throws IOException {
		super(manager, productOffer);
		this.nextMax = (double) productOffer.maxAmount;
	}
	
	/*
	 * Finishes the auction if necessary
	 */
	public boolean finish() {
		int biddings = this.biddings.size();
		if(biddings > 0) {
			Bidding highest = this.biddings.get(biddings-1);
			
			//Determine amount
			double productAmount = (double) highest.amount;
			double auctionAmount = this.calculateAmount();
			double shippingAmount = this.calcShippingPrice(highest.address, productAmount);
			
			//Check if somebody is willing to pay
			if(productAmount > (double) this.nextMax) {
				
				//Transfer money
				try {
					this.transferMoney(highest.bank, highest.bankAccountID, auctionAmount, productAmount, shippingAmount);
				} catch(Exception e) {
					this.restart();
					this.nextMax = this.maxAmount;
					e.printStackTrace();
					return false;
				}
				
				//Notify customers and the winner
				this.notifyCustomers("Product " + this.product.getName() + " has been sold for € " + Double.toString(productAmount));
				try {
					highest.customer.notify(new WinningEvent("Auctioneer", 0, 0, null, "Congratulations! You've won the auction for product " + this.product.getName(), this.product));
				} catch (RemoteException e) {
					System.out.println("[DUTCHAUCTIONEER] The winner couldn't be notified.");
				} catch (UnknownEventException e) {
					System.out.println("[DUTCHAUCTIONEER] The winner couldn't be notified.");
				}				
				
				//Ship product
				this.shipProduct(highest.address, productAmount);
				try {
					while(this.getShippingState() != ShippingState.ARRIVED) {
						Thread.sleep(1000);
					}
				} catch (Exception e) {
					System.out.println("[DUTCHAUCTIONEER] Error receiving shipping updates.");
				}
				System.out.println("[DUTCHAUCTIONEER] The product was delivered to the buyer.");
				
				return true;
			} else {
				return false;
			}
		}

		return false;
	}

	public void run() {
		while(true) {
			try {
				//Find new information
				this.findCustomers();
				this.notifyCustomers("Current price for product " + this.product.getName() + ": " + this.nextMax);
				this.findBiddings();
				
				//Process information
				if(this.hasNewBiddings()) {
					if(this.finish()) {
						break;
					}
				}
				
				//Lower the price
				if(this.nextMax > this.minAmount) {
					this.nextMax = this.nextMax - this.nextMax * 0.1;
				}
				if(this.nextMax <= this.minAmount) {
					this.nextMax = this.minAmount;
				}
			} catch (LeaseDeniedException e1) {
				e1.printStackTrace();
			} catch (RemoteException e1) {
				e1.printStackTrace();
			} catch (UnusableEntryException e1) {
				e1.printStackTrace();
			} catch (TransactionException e1) {
				e1.printStackTrace();
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			
			//Sleep
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("[AUCTIONEER] Auction closed");
	}
	
	/**
	 * Abstract methods 
	 */
	public abstract double calculateAmount();

}
